use tracing::debug;

use crate::ast_define::{MetaInfo, declear::*, function::*, statement::*};
use crate::semantic_analysis::symbol_table::ScopeType;
use crate::semantic_analysis::{SemanticError, SemanticErrorType, Symbol, SymbolType, Type};

impl super::TypeChecker {
    /// 检查语句块
    pub fn check_block(&mut self, block: &Block) {
        self.symbol_table.enter_scope(ScopeType::Block);
        for block_item in &block.block_item {
            self.check_block_item(block_item);
        }
        self.symbol_table.exit_scope();
    }

    /// 检查块项
    pub fn check_block_item(&mut self, block_item: &BlockItem) {
        match block_item {
            BlockItem::Decl(decl) => {
                self.check_local_decl(decl);
            }
            BlockItem::Stmt(stmt) => {
                self.check_stmt(stmt);
            }
        }
    }

    /// 检查局部声明
    pub fn check_local_decl(&mut self, decl: &Decl) {
        // ! 不存在local const定义, 不用检查了
        if let Decl::VarDecl(var_decl) = decl {
            for var_def in &var_decl.var_def {
                self.check_local_var_def(var_def);
            }
        }
    }

    /// 检查局部变量定义
    pub fn check_local_var_def(&mut self, var_def: &VarDef) {
        // 先检查表达式
        self.check_var_def(var_def);

        // 然后定义符号
        let (ident, const_exp, init_val) = match var_def {
            VarDef::Ident_ConstExp_Brackets_Wrapper_Assign_InitVal(def) => {
                (&def.ident, &def.const_exp, Some(&def.init_val))
            }
            VarDef::Ident_ConstExp_Brackets_Wrapper(def) => (&def.ident, &def.const_exp, None),
        };

        let var_type = match const_exp.is_empty() {
            true => Type::Int,
            false => Type::Array(const_exp.len()),
        };

        let symbol = Symbol::new(
            ident.value.clone(),
            SymbolType::Variable(var_type),
            ident.meta_info.clone(),
        );

        // 验重
        if self
            .symbol_table
            .check_redefine(&symbol.name, &symbol.symbol_type)
            .is_err()
        {
            self.errors.push(SemanticError::redefined_variable(
                &symbol.name,
                symbol.location.clone(),
            ));
            return;
        }
        self.symbol_table.define(symbol);
    }

    /// 检查语句
    pub fn check_stmt(&mut self, stmt: &Stmt) {
        match stmt {
            Stmt::If_Stmt(if_stmt) => self.check_if_stmt(if_stmt),
            Stmt::Return_Stmt(return_stmt) => self.check_return_stmt(return_stmt),
            Stmt::Block(block) => self.check_block(block),
            Stmt::LVal_Assign_Exp_Stmt(assign_stmt) => self.check_assign_stmt(assign_stmt),
            Stmt::Exp_Stmt(exp_stmt) => self.check_exp_stmt(exp_stmt),
            Stmt::While_Stmt(while_stmt) => self.check_while_stmt(while_stmt),
            Stmt::Break_Stmt(_) | Stmt::Continue_Stmt(_) => {}
        }
    }

    /// 检查if语句
    pub fn check_if_stmt(&mut self, if_stmt: &If_Stmt) {
        self.check_cond(&if_stmt.cond);
        self.check_stmt(&if_stmt.stmt);

        if let Some(else_stmt) = &if_stmt.else_stmt {
            self.check_stmt(&else_stmt.stmt);
        }
    }

    /// 检查while语句
    pub fn check_while_stmt(&mut self, while_stmt: &While_Stmt) {
        self.check_cond(&while_stmt.cond);
        self.check_stmt(&while_stmt.stmt);
    }

    /// 检查return语句
    pub fn check_return_stmt(&mut self, return_stmt: &Return_Stmt) {
        let expected_type = self
            .current_function_return_type
            .clone()
            .expect("Return statement outside function");

        match &return_stmt.exp {
            Some(exp) => {
                let actual_type = self.check_exp(exp);
                if let Some(actual_type) = actual_type
                    && !expected_type.is_assignable_from(&actual_type)
                {
                    self.errors.push(SemanticError::type_mismatched_for_return(
                        return_stmt.meta_info.clone(),
                    ));
                }
            }
            None => {
                if expected_type != Type::Void {
                    self.errors.push(SemanticError::type_mismatched_for_return(
                        return_stmt.meta_info.clone(),
                    ));
                }
            }
        }
    }

    /// 检查表达式语句
    pub fn check_exp_stmt(&mut self, exp_stmt: &Exp_Stmt) {
        if let Some(exp) = &exp_stmt.exp {
            self.check_exp(exp);
        }
    }
}
